#pragma once

#include <sys/epoll.h>
#include "Epoller.hpp"
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Connection.hpp"

using namespace EpollModule;
using connection_t = std::shared_ptr<Connection>;
class Reactor
{
    const static int event_num = 64;

private:
    bool IsConnectionExists(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

public:
    Reactor() : _isrunning(false), _epoller(std::make_unique<Epoller>())
    {
        // 创建epoll模型
        _epoller->Init();
    }

    // 插入新连接，同时还要把方法传进来
    // listensockfd也是这么插入进来的，只需要在创建的时候，设置不同的回调方法即可
    void InsertConnection(connection_t conn)
    {
        // 判断连接是否已经存在
        auto iter = _connections.find(conn->SockFd());
        if (iter == _connections.end())
        {
            // 1，把连接放到unordered_map中进行管理
            _connections.insert({conn->SockFd(), conn});
             // 2, 把新插入进来的连接，对应的fd，写透到内核的epoll中
            _epoller->Add(conn->SockFd(), conn->GetEvents());
            LOG(LogLevel::INFO) << "插入新连接: " << conn->SockFd();
            // 3, 设置关联关系，让connection回指当前对象
            conn->SetOwner(this);
        }
    }
    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {
        if(IsConnectionExists(sockfd))
        {
            // 修改用户层connection的事件
            uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
            _connections[sockfd]->SetEvents(events);
            // 写透到内核中
            _epoller->Update(sockfd, _connections[sockfd]->GetEvents()); 
        }
    }
    void DelConnection(int sockfd)
    {
        if(IsConnectionExists(sockfd))
        {
            // 1.从epoll中移除事件监控
            _epoller->Delete(sockfd);
            // 2.关闭特定的文件描述符
            _connections[sockfd]->Close();
            // 3.从unordered_map中移除
            _connections.erase(sockfd);
        }
    }
    // 基于事件驱动的事件派发器
    void Dispatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            // 对已经就绪的事件进行派发
            // 派发给指定的模块
            int sockfd = _revs[i].data.fd;
            LOG(LogLevel::INFO) << "派发事件: " << sockfd;
            uint32_t revents = _revs[i].events;
            if ((revents & EPOLLERR) || (revents & EPOLLHUP))
            {
                revents = (EPOLLIN | EPOLLOUT); // 把异常事件，转换成为读写事件，这样是为了把异常的处理都集合到同一个函数中
            }
            if ((revents & EPOLLIN) && IsConnectionExists(sockfd))
            {
                // 如果是读事件，就直接调用conn设置好的对应事件的回调函数
                // 如果是listensockfd，则最终回调用Acceptor()方法
                // 把连接自己传进去
                _connections[sockfd]->Recver();
            }
            if ((revents & EPOLLOUT) && IsConnectionExists(sockfd))
            {
                _connections[sockfd]->Sender();
            }
        }
    }
    void LoopOnce(int timeout)
    {
        int n = _epoller->Wait(_revs, event_num, timeout);
        Dispatcher(n);
    }
    void DebugPrint()
    {
        std::cout << "Epoller 管理的fd: ";
        for (auto &it : _connections)
        {
            std::cout << it.first << " ";
        }
        std::cout << std::endl;
    }
    void Loop()
    {
        _isrunning = true;
        int timeout = 1000;// 事件监控一秒钟返回一次，这样就可以在循环中每隔一秒检测一下是否有连接超时
        while (_isrunning)
        {   
            LoopOnce(timeout);
            DebugPrint();
            // 超时管理
            // 简单的，遍历_connections, 判断当前时间，-connection的最近访问时间是否 > 某个值
            // 这样就超时了
        }
        _isrunning = false;
    }

    void Stop()
    {
        _isrunning = false;
    }
    ~Reactor() {}

private:
    uint16_t _port;
    std::unique_ptr<Epoller> _epoller;
    // 服务器内部所有的连接，通过文件描述符找对应的连接
    std::unordered_map<int, connection_t> _connections;
    bool _isrunning;
    struct epoll_event _revs[event_num];
};